package com.example.utils;

import com.example.entity.result.Result;
import com.example.entity.result.ResultBean;
import com.example.entity.vo.Car;
import com.example.entity.vo.Order;
import com.example.entity.vo.User;
import com.example.exception.OperatorException;
import com.example.exception.ServiceException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.util.StringUtils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.BiFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
 * 数据工具包
 */
public class DataUtils {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static ObjectMapper getObjectMapper() {
        return objectMapper;
    }

    /**
     * 数据比较
     *
     * @param o1,o2 比较数据
     * @param clazz 数据类型
     * @return 对比度 0-1
     */
    public static <T> float dataCompare(Object o1, Object o2, Class<T> clazz) {
        int count = 0;
        Field[] declaredFields = clazz.getDeclaredFields();
        try {
            for (Field field : declaredFields) {
                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                Method getMethod = pd.getReadMethod();
                Object object1 = getMethod.invoke(o1);
                Object object2 = getMethod.invoke(o2);
                if (object1 == null && object2 == null) {
                    count++;
                }
                if (object1 != null && object2 != null && object1.toString().equals(object2.toString())) {
                    count++;
                }
            }
        } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return (float) count / declaredFields.length;
    }

    public static String getJSON(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 请求结果装配
     *
     * @param code 请求状态码
     * @param obj  请求参数 obj[0]为返回信息
     * @return result
     */
    public static Result getResult(int code, Object... obj) {
        Result result = new Result();
        result.setCode(code);
        if (obj.length >= 1) {
            result.setMsg((String) obj[0]);
            HashMap<String, Object> map = new HashMap<>();
            for (int i = 1; i < obj.length; i++) {
                Object o = obj[i];
                if (o instanceof HashMap && !typeConversionMap(o).isEmpty()) {
                    map.putAll(typeConversionMap(o));
                } else {
                    if (map.isEmpty()) {
                        if (obj.length > 2) {
                            List<Object> list = new ArrayList<>();
                            list.add(o);
                            map.put("data", list);
                        } else {
                            map.put("data", o);
                        }
                        continue;
                    }
                    map.merge("data", o, (BiFunction<Object, Object, List<Object>>) (o1, o2) -> {
                        List<Object> list = castList(o1, Object.class);
                        if (list.get(0).getClass().getSimpleName().equals("ArrayList")) {
                            List<Object> temp = castList(list.get(0), Object.class);
                            if (temp.get(0).getClass().getSimpleName().equals(o2.getClass().getSimpleName())) {
                                temp.add(o2);
                                list = temp;
                            } else {
                                list.add(o2);
                            }
                        } else {
                            list.add(o2);
                        }
                        return list;
                    });
                }
            }
            result.setMap(map);
        }

        return result;
    }

    //封装
    public static ResultBean getResultBean(int code, String clazz, Object... obj) {
        Result result = getResult(code, obj);
        ResultBean resultBean = new ResultBean(result.getCode(), result.getMsg());
        resultBean.setMap(ObjectToJson(result.getMap()));
        resultBean.setType(clazz);
        return resultBean;
    }

    public static ResultBean getResultBean(Result result, String clazz) {
        ResultBean resultBean = new ResultBean(result.getCode(), result.getMsg());
        resultBean.setMap(ObjectToJson(result.getMap()));
        resultBean.setType(clazz);
        return resultBean;
    }

    public static ResultBean getResultBean(Result result) {
        ResultBean resultBean = new ResultBean(result.getCode(), result.getMsg());
        resultBean.setMap(ObjectToJson(result.getMap()));
        resultBean.setType("");
        return resultBean;
    }

    //获取user
    public static User getUser(String json) {
        User user;
        try {
            user = objectMapper.readValue(json, User.class);
        } catch (JsonProcessingException e) {
            throw new ServiceException("解析异常");
        }
        return user;
    }

    //获取Order
    public static Order getOrder(String json) {
        Order order;
        try {
            order = objectMapper.readValue(json, Order.class);
        } catch (JsonProcessingException e) {
            throw new ServiceException("解析异常");
        }
        return order;
    }

    //获取Order
    public static Car getCar(String json) {
        Car car;
        try {
            car = objectMapper.readValue(json, Car.class);
        } catch (JsonProcessingException e) {
            throw new ServiceException("解析异常");
        }
        return car;
    }

    //object转map
    public static <K, V> Map<K, V> typeConversionMap(Object obj, Class<K> tClass, Class<V> vClass) {
        HashMap<K, V> result = new HashMap<>();
        if (obj instanceof Map<?, ?>) {
            Map<?, ?> map = (Map<?, ?>) (obj);
            for (Map.Entry<?, ?> entry : map.entrySet()) {
                result.put(tClass.cast(entry.getKey()), vClass.cast(entry.getValue()));
            }
        }
        return result;
    }

    //object转map
    public static Map<String, Object> typeConversionMap(Object obj) {
        return typeConversionMap(obj, Object.class);
    }

    //object转map
    public static <V> Map<String, V> typeConversionMap(Object obj, Class<V> vClass) {
        return typeConversionMap(obj, String.class, vClass);
    }

    //Object转List集合
    public static <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<>();
        if (obj instanceof List<?>) {
            for (Object o : (List<?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }

    //测试工具
    public static <T> T textUtils(Class<T> clazz) {
        T t = null;
        try {
            Constructor<T> c = clazz.getConstructor();
            t = c.newInstance();
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                Method getWriteMethod = pd.getWriteMethod();
                Class<?>[] parameterTypes = getWriteMethod.getParameterTypes();
                if (parameterTypes.length == 1) {
                    String typeName = parameterTypes[0].getSimpleName();
                    if (typeName.equals("int")) {
                        getWriteMethod.invoke(t, (int) (Math.random() * 10));
                    }
                    if (typeName.equals("float")) {
                        getWriteMethod.invoke(t, 10.00f);
                    }
                    if (typeName.equals("String")) {
                        getWriteMethod.invoke(t,
                                getRandomStr((int) (Math.random() * 5)) + (int) (Math.random() * 20));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return t;
    }

    /**
     * 1.生成的字符串每个位置都有可能是str中的一个字母或数字，需要导入的包是import java.util.Random;
     *
     * @param length 字符串长度
     */
    public static String getRandomStr(int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuilder stringBuffer = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            stringBuffer.append(str.charAt(number));
        }
        return stringBuffer.toString();
    }

    /**
     * 参数为空校验
     */
    public static void paramCheckEmpty(String key, String value) {
        if (key == null || StringUtils.isEmpty(key)) {
            throw new OperatorException("参数不能为空", Result.PARAMETER_EMPTY);
        }
        if (!key.equals("all") && (StringUtils.isEmpty(value) || "NAN".equals(value))) {
            throw new OperatorException("参数不能为空", Result.PARAMETER_EMPTY);
        }
    }

    public static void paramCheckEmpty(String key, List<String> value) {
        if (key == null || StringUtils.isEmpty(key)) {
            throw new OperatorException("参数不能为空", Result.PARAMETER_EMPTY);
        }
        if (!key.equals("all")) {
            for (String v : value) {
                if (StringUtils.isEmpty(v)) {
                    throw new OperatorException("参数不能为空", Result.PARAMETER_EMPTY);
                }
            }
        }
    }

    public static void paramCheckEmpty(String key, HashMap<String, String> value) {
        if (key == null || StringUtils.isEmpty(key)) {
            throw new OperatorException("参数不能为空", Result.PARAMETER_EMPTY);
        }
        if (!key.equals("all")) {
            for (Map.Entry<String, String> entry : value.entrySet()) {
                if (StringUtils.isEmpty(entry.getValue())) {
                    throw new OperatorException("参数不能为空", Result.PARAMETER_EMPTY);
                }
            }
        }
    }


    //参数转int
    public static int paramToInteger(String key) {
        int id;
        try {
            id = Integer.parseInt(key);
        } catch (Exception e) {
            throw new OperatorException("参数不正确: " + e.getMessage(), Result.PARAMETER_TYPE_ERROR);
        }
        return id;
    }

    //参数转int
    public static float paramToFloat(String key) {
        float id;
        try {
            id = Float.parseFloat(key);
        } catch (Exception e) {
            throw new OperatorException("参数不正确: " + e.getMessage(), Result.PARAMETER_TYPE_ERROR);
        }
        return id;
    }


    //参数转list
    public static List<String> jsonToList(String json) {
        List<String> list;
        try {
            list = objectMapper.readValue(json, new TypeReference<List<String>>() {
            });
        } catch (JsonProcessingException e) {
            throw new ServiceException("JSON解析异常");
        }
        return list;
    }

    //参数转Map
    public static HashMap<String, String> jsonToMap(String json) {
        HashMap<String, String> map;
        try {
            map = objectMapper.readValue(json, new TypeReference<HashMap<String, String>>() {
            });
        } catch (JsonProcessingException e) {
            throw new OperatorException("参数类型错误", Result.PARAMETER_TYPE_ERROR);
        }
        return map;
    }

    public static String ObjectToJson(HashMap<?, ?> map) {
        try {
            return objectMapper.writeValueAsString(map);
        } catch (JsonProcessingException e) {
            throw new OperatorException("解析异常");
        }
    }

    public static boolean isChinaPhoneLegal(String str) throws PatternSyntaxException {
        String regExp = "^((13[0-9])|(15[^4])|(18[0,2,3,5-9])|(17[0-8])|(147))\\d{8}$";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(str);
        return m.matches();
    }
}
